﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ParserCore;
using QLabValues;
using NumericalCalculations;
using AtomicTypes;
using Memory_Access;

namespace Engine
{
    public class EngineFunctions
    {
        /// <summary>
        /// These functions use Engine tables.
        /// </summary>
        public static Dictionary<Identifier, Functions.f> FunctionsDictionary;

        public void AddFunctions()
        {
            FunctionsDictionary = new Dictionary<Identifier, Functions.f>();

            FunctionsDictionary.Add(new Identifier("accumarray"), accumarray);
            // TODO: add engine functions in FunctionsDictionary
        }

        // TODO: implement engine functions

        //fja kreira niz akumuliranjem prosledjenog niza
        //NAPOMENA: DEO KOJI SE ODNOSI NA SPARSE MATRICE NIJE IMPLEMENTIRAN!!!
        public List<IQLabValue> accumarray(List<IQLabValue> o)
        {
            //fja prima od 2 do 6 argumenata
            if (o.Count < 2)
                throw new NumericalCalculationsException("??? Error using ==> accumarray \n Not enough input arguments.");
            if(o.Count > 6)
                throw new NumericalCalculationsException("??? Error using ==> accumarray \n Too many input arguments.");

            QFloat64NDimArray subsArray;    //prvi argument - pozicije u novom nizu
            QFloat64NDimArray valArray;     //drugi argument - niz od koga se akumuliranjem dobija novi niz
            int[] newDim;                   //dimenzije novog niza
            bool isSparse = false;          //da li se novi niz popunjava (sa vrednoscu fillValue) na mestima koja nisu navedena u subsArray
                                            //ili ce se kreirati sparse matrica. Napomena: sparse matrice jos uvek nisu podrzane u Qlab-u            
            bool isFillValue = false;       //da li je prosledjen argument fillValue

            QFloat64NDimArray fillValueArray = null;    //vrednost kojom se popunjavaju 'prazne' pozicije nove matrice
            Identifier fun = new Identifier("sum");     //funkcija akumulacije je po defaultu 'sum'

            bool isValScalar = false;

            if(o.ElementAt(0).GetEnumType() == IQLabValueType.QBooleanNDimArray)
                throw new NumericalCalculationsException("??? Error using ==> accumarray \n First input SUBS must be a real, full, numeric matrix or a cell vector.");

            if(o.ElementAt(0).GetEnumType() == IQLabValueType.QCharNDimArray || !Helper.canConvertToEnum(o.ElementAt(0), IQLabValueType.QFloat64NDimArray))
                throw (new NumericalCalculationsException("??? Undefined function or method 'accumarray' for input arguments of type " +
                    Helper.PrintEnumName(o.ElementAt(0).GetEnumType()) + "."));

            subsArray = new QFloat64NDimArray(o.ElementAt(0));

            if(subsArray.Dimension > 2 || subsArray.Data.Length == 0)
                throw (new NumericalCalculationsException("??? Undefined function or method 'accumarray' for input arguments of type " +
                    Helper.PrintEnumName(o.ElementAt(0).GetEnumType()) + " and attributes 'full 3d real'."));

            if(!Helper.canConvertToEnum(o.ElementAt(1), IQLabValueType.QFloat64NDimArray))
                throw (new NumericalCalculationsException("??? Undefined function or method 'accumarray' for input arguments of type " +
                    Helper.PrintEnumName(o.ElementAt(1).GetEnumType()) + "."));
            
            valArray = new QFloat64NDimArray(o.ElementAt(1));
            if(valArray.Dimension > 2 || (valArray.DimensionSize[0] != 1 && valArray.DimensionSize[1] != 1))
                throw new NumericalCalculationsException("??? Error using ==> accumarray \n Second input VAL must be a vector with one element for each row in SUBS, or a scalar.");

            isValScalar = Helper.checkIfScalar(valArray);
            if ((valArray.Data.Length != subsArray.DimensionSize[0]) && !isValScalar)
                throw new NumericalCalculationsException("??? Error using ==> accumarray \n Second input VAL must be a vector with one element for each row in SUBS, or a scalar.");

            //velicina novog niza
            if (subsArray.DimensionSize[1] <= 1)
            {
                newDim = new int[2];
                newDim[1] = 1;
            }
            else
                newDim = new int[subsArray.DimensionSize[1]];
            
            //dimenzije su maksimalne vrednosti kolona subsArray
            for (int i = 0; i < subsArray.DimensionSize[0]; i++)
                for (int j = 0; j < subsArray.DimensionSize[1]; j++)
                {
                    if (subsArray.Data[i + j * subsArray.DimensionSize[0]].IsComplex())
                        throw new NumericalCalculationsException("??? Error using ==> accumarray \n First input SUBS must be a real, full, numeric matrix or a cell vector.");

                    if (subsArray.Data[i + j * subsArray.DimensionSize[0]].Real <= 0 || subsArray.Data[i + j * subsArray.DimensionSize[0]].Real != (int)subsArray.Data[i + j * subsArray.DimensionSize[0]].Real)
                        throw new NumericalCalculationsException("??? Error using ==> accumarray \n First input SUBS must contain positive integer subscripts.");

                    if (newDim[j] < subsArray.Data[i + j * subsArray.DimensionSize[0]].Real)
                        newDim[j] = (int)subsArray.Data[i + j * subsArray.DimensionSize[0]].Real;
                }

            //prosledjeno je najmanje tri argumenta
            if (o.Count > 2)
            {
                if(o.ElementAt(2).GetEnumType() == IQLabValueType.QCharNDimArray)
                    throw new NumericalCalculationsException("??? Error using ==> accumarray \n Third input SZ must be a full row vector with one element for each column of SUBS.");

                if (!Helper.canConvertToEnum(o.ElementAt(2), IQLabValueType.QFloat64NDimArray))
                    throw (new NumericalCalculationsException("??? Undefined function or method 'accumarray' for input arguments of type " +
                        Helper.PrintEnumName(o.ElementAt(2).GetEnumType()) + "."));

                QFloat64NDimArray newDimArray = new QFloat64NDimArray(o.ElementAt(2));
                //u slucaju da je prosledjen prazan niz ne radi se nista, koriste se default vrednosti
                if (newDimArray.Data.Length != 0)
                {
                    if(newDimArray.Dimension > 2 || newDimArray.DimensionSize[0] != 1)
                        throw new NumericalCalculationsException("??? Error using ==> accumarray \n Third input SZ must be a full row vector with one element for each column of SUBS.");

                    //ako je subsArray kolona
                    if (subsArray.DimensionSize[1] == 1)
                    {
                        if (newDimArray.Data.Length != 2)
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n Third input SZ must be a full row vector with one element for each column of SUBS.");

                        if (newDimArray.Data[0].IsComplex() || newDimArray.Data[1].IsComplex())
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n Size vector must be a row vector with real elements.");

                        if ((int)newDimArray.Data[1].Real != 1)
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n When SUBS is a column vector, the third input SZ must be of the form [N 1].");

                        if (newDimArray.Data[0].Real < newDim[0])
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n First input SUBS and third input SZ must satisfy ALL(MAX(SUBS)<=SZ).");

                        newDim[0] = (int)newDimArray.Data[0].Real;
                    }
                    //subsArray je matrica sa vise kolona
                    else
                    {
                        if (newDimArray.Data.Length != newDim.Length)
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n Third input SZ must be a full row vector with one element for each column of SUBS.");

                        for (int i = 0; i < newDimArray.Data.Length; i++)
                        {
                            if(newDimArray.Data[i].IsComplex())
                                throw new NumericalCalculationsException("??? Error using ==> accumarray \n Size vector must be a row vector with real elements.");

                            if (newDimArray.Data[i].Real < newDim[i])
                                throw new NumericalCalculationsException("??? Error using ==> accumarray \n First input SUBS and third input SZ must satisfy ALL(MAX(SUBS)<=SZ).");

                            newDim[i] = (int)newDimArray.Data[i].Real;
                        }
                    }
                }
            }

            //prosledjeno je najmanje cetiri argumenta
            if (o.Count > 3)
            {
                if(o.ElementAt(3).GetEnumType() != IQLabValueType.QFunctionHandle)
                    throw new NumericalCalculationsException("??? Error using ==> accumarray \n Fourth input FUN must be a function handle.");

                QFunctionHandle fh = o.ElementAt(3) as QFunctionHandle;
                fun = fh.GetFunctionHandle();
            }

            //prosledjeno je najmanje 5 argumenata
            if (o.Count > 4)
            {
                if(!Helper.canConvertToEnum(o.ElementAt(4), IQLabValueType.QFloat64NDimArray))
                    throw (new NumericalCalculationsException("??? Undefined function or method 'accumarray' for input arguments of type " +
                        Helper.PrintEnumName(o.ElementAt(4).GetEnumType()) + "."));
                
                fillValueArray = new QFloat64NDimArray(o.ElementAt(4));

                if(!Helper.checkIfScalar(fillValueArray))
                    throw new NumericalCalculationsException("??? Error using ==> accumarray \n Fifth input FILLVALUE must be a full scalar.");

                isFillValue = true;
            }

            //prosledjeno je 6 argumenata
            if (o.Count > 5)
            {
                if(!Helper.canConvertToEnum(o.ElementAt(5), IQLabValueType.QBooleanNDimArray))
                    throw new NumericalCalculationsException("??? Error using ==> accumarray \n Sixth input ISSPARSE must be a logical scalar.");
                
                QBooleanNDimArray isSparseArray = new QBooleanNDimArray(o.ElementAt(5));

                if (!Helper.checkIfScalar(isSparseArray))
                    throw new NumericalCalculationsException("??? Error using ==> accumarray \n Sixth input ISSPARSE must be a logical scalar.");

                isSparse = isSparseArray.Data[0].Real;
            }


            //recnik ciji je kljuc nova pozicija, a vrednost je lista starih pozicija
            Dictionary<int, List<int>> newListOld = new Dictionary<int, List<int>>();
            for (int i = 0; i < subsArray.DimensionSize[0]; i++)
            {
                int pos = (int)subsArray.Data[i + (subsArray.DimensionSize[1] - 1) * subsArray.DimensionSize[0]].Real - 1;
                for (int j = subsArray.DimensionSize[1] - 2; j >= 0; j--)
                    pos = pos * newDim[j] + (int)subsArray.Data[i + j * subsArray.DimensionSize[0]].Real - 1;

                List<int> l;
                bool succes = newListOld.TryGetValue(pos, out l);
                if (succes)
                {
                    if (isValScalar)
                        l.Add(0);
                    else
                        l.Add(i);
                }
                else
                {
                    l = new List<int>();
                    if (isValScalar)
                        l.Add(0);
                    else
                        l.Add(i);
                    newListOld[pos] = l;
                }
            }

            FunctionImplementation calledFun = Engine.EngineManager.Instance.pathFuncTable.LookUp(fun);
            if(calledFun == null)
                throw (new NumericalCalculationsException("??? Undefined function or method '" + fun.ID + "' for input arguments of type " +
                        Helper.PrintEnumName(o.ElementAt(1).GetEnumType()) + "."));

            if (!isSparse)
            {
                var x = newListOld.ElementAt(0);
                List<IQLabValue> funArgs = new List<IQLabValue>();
                IQLabValue funRes;
                int n = x.Value.Count;
                List<IQLabValue> res = new List<IQLabValue>();

                if (o.ElementAt(1).GetEnumType() == IQLabValueType.QBooleanNDimArray)
                {
                    QBoolean[] val = new QBoolean[n];
                    for (int i = 0; i < n; i++)
                        val[i] = new QBoolean(valArray.Data[x.Value.ElementAt(i)]);

                    funArgs.Add(new QBooleanNDimArray(val, 1, n));
                    funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                    if (funRes.GetEnumType() == IQLabValueType.QBooleanNDimArray)
                    {
                        if(isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QBooleanNDimArray resVal = new QBooleanNDimArray(newDim);
                        QBoolean fillValue;

                        if (isFillValue)
                            fillValue = new QBoolean(fillValueArray.Data[0]);
                        else
                            fillValue = new QBoolean(false);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QBoolean[] vals = new QBoolean[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QBoolean(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QBooleanNDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QBooleanNDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QBoolean(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QCharNDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QCharNDimArray resVal = new QCharNDimArray(newDim);
                        QChar fillValue;

                        if (isFillValue)
                            fillValue = new QChar(fillValueArray.Data[0]);
                        else
                            fillValue = new QChar('\0');

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QBoolean[] vals = new QBoolean[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QBoolean(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QBooleanNDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QCharNDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QChar(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QInt64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QInt64NDimArray resVal = new QInt64NDimArray(newDim);
                        QInt64 fillValue;

                        if (isFillValue)
                            fillValue = new QInt64(fillValueArray.Data[0]);
                        else
                            fillValue = new QInt64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QBoolean[] vals = new QBoolean[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QBoolean(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QBooleanNDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QInt64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QInt64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QUInt64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QUInt64NDimArray resVal = new QUInt64NDimArray(newDim);
                        QUInt64 fillValue;

                        if (isFillValue)
                            fillValue = new QUInt64(fillValueArray.Data[0]);
                        else
                            fillValue = new QUInt64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QBoolean[] vals = new QBoolean[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QBoolean(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QBooleanNDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QUInt64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QUInt64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QFloat64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QFloat64NDimArray resVal = new QFloat64NDimArray(newDim);
                        QFloat64 fillValue;

                        if (isFillValue)
                            fillValue = new QFloat64(fillValueArray.Data[0]);
                        else
                            fillValue = new QFloat64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QBoolean[] vals = new QBoolean[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QBoolean(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QBooleanNDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QFloat64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QFloat64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }
                    else
                        throw (new NumericalCalculationsException("??? Undefined function or method 'accumarray' for input arguments of type " +
                            Helper.PrintEnumName(funRes.GetEnumType()) + "."));
                }


                else if (o.ElementAt(1).GetEnumType() == IQLabValueType.QCharNDimArray)
                {
                    QChar[] val = new QChar[n];
                    for (int i = 0; i < n; i++)
                        val[i] = new QChar(valArray.Data[x.Value.ElementAt(i)]);

                    funArgs.Add(new QCharNDimArray(val, 1, n));
                    funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                    if (funRes.GetEnumType() == IQLabValueType.QBooleanNDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QBooleanNDimArray resVal = new QBooleanNDimArray(newDim);
                        QBoolean fillValue;

                        if (isFillValue)
                            fillValue = new QBoolean(fillValueArray.Data[0]);
                        else
                            fillValue = new QBoolean(false);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QChar[] vals = new QChar[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QChar(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QCharNDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QBooleanNDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QBoolean(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QCharNDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QCharNDimArray resVal = new QCharNDimArray(newDim);
                        QChar fillValue;

                        if (isFillValue)
                            fillValue = new QChar(fillValueArray.Data[0]);
                        else
                            fillValue = new QChar('\0');

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QChar[] vals = new QChar[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QChar(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QCharNDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QCharNDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QChar(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QInt64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QInt64NDimArray resVal = new QInt64NDimArray(newDim);
                        QInt64 fillValue;

                        if (isFillValue)
                            fillValue = new QInt64(fillValueArray.Data[0]);
                        else
                            fillValue = new QInt64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QChar[] vals = new QChar[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QChar(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QCharNDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QInt64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QInt64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QUInt64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QUInt64NDimArray resVal = new QUInt64NDimArray(newDim);
                        QUInt64 fillValue;

                        if (isFillValue)
                            fillValue = new QUInt64(fillValueArray.Data[0]);
                        else
                            fillValue = new QUInt64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QChar[] vals = new QChar[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QChar(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QCharNDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QUInt64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QUInt64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QFloat64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QFloat64NDimArray resVal = new QFloat64NDimArray(newDim);
                        QFloat64 fillValue;

                        if (isFillValue)
                            fillValue = new QFloat64(fillValueArray.Data[0]);
                        else
                            fillValue = new QFloat64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QChar[] vals = new QChar[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QChar(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QCharNDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QFloat64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QFloat64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }
                    else
                        throw (new NumericalCalculationsException("??? Undefined function or method 'accumarray' for input arguments of type " +
                            Helper.PrintEnumName(funRes.GetEnumType()) + "."));
                }


                else if (o.ElementAt(1).GetEnumType() == IQLabValueType.QInt64NDimArray)
                {
                    QInt64[] val = new QInt64[n];
                    for (int i = 0; i < n; i++)
                        val[i] = new QInt64(valArray.Data[x.Value.ElementAt(i)]);

                    funArgs.Add(new QInt64NDimArray(val, 1, n));
                    funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                    if (funRes.GetEnumType() == IQLabValueType.QBooleanNDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QBooleanNDimArray resVal = new QBooleanNDimArray(newDim);
                        QBoolean fillValue;

                        if (isFillValue)
                            fillValue = new QBoolean(fillValueArray.Data[0]);
                        else
                            fillValue = new QBoolean(false);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QInt64[] vals = new QInt64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QInt64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QInt64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QBooleanNDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QBoolean(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QCharNDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QCharNDimArray resVal = new QCharNDimArray(newDim);
                        QChar fillValue;

                        if (isFillValue)
                            fillValue = new QChar(fillValueArray.Data[0]);
                        else
                            fillValue = new QChar('\0');

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QInt64[] vals = new QInt64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QInt64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QInt64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QCharNDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QChar(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QInt64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QInt64NDimArray resVal = new QInt64NDimArray(newDim);
                        QInt64 fillValue;

                        if (isFillValue)
                            fillValue = new QInt64(fillValueArray.Data[0]);
                        else
                            fillValue = new QInt64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QInt64[] vals = new QInt64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QInt64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QInt64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QInt64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QInt64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QUInt64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QUInt64NDimArray resVal = new QUInt64NDimArray(newDim);
                        QUInt64 fillValue;

                        if (isFillValue)
                            fillValue = new QUInt64(fillValueArray.Data[0]);
                        else
                            fillValue = new QUInt64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QInt64[] vals = new QInt64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QInt64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QInt64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QUInt64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QUInt64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QFloat64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QFloat64NDimArray resVal = new QFloat64NDimArray(newDim);
                        QFloat64 fillValue;

                        if (isFillValue)
                            fillValue = new QFloat64(fillValueArray.Data[0]);
                        else
                            fillValue = new QFloat64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QInt64[] vals = new QInt64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QInt64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QInt64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QFloat64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QFloat64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }
                    else
                        throw (new NumericalCalculationsException("??? Undefined function or method 'accumarray' for input arguments of type " +
                            Helper.PrintEnumName(funRes.GetEnumType()) + "."));
                }



                else if (o.ElementAt(1).GetEnumType() == IQLabValueType.QUInt64NDimArray)
                {
                    QUInt64[] val = new QUInt64[n];
                    for (int i = 0; i < n; i++)
                        val[i] = new QUInt64(valArray.Data[x.Value.ElementAt(i)]);

                    funArgs.Add(new QUInt64NDimArray(val, 1, n));
                    funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                    if (funRes.GetEnumType() == IQLabValueType.QBooleanNDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QBooleanNDimArray resVal = new QBooleanNDimArray(newDim);
                        QBoolean fillValue;

                        if (isFillValue)
                            fillValue = new QBoolean(fillValueArray.Data[0]);
                        else
                            fillValue = new QBoolean(false);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QUInt64[] vals = new QUInt64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QUInt64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QUInt64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QBooleanNDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QBoolean(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QCharNDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QCharNDimArray resVal = new QCharNDimArray(newDim);
                        QChar fillValue;

                        if (isFillValue)
                            fillValue = new QChar(fillValueArray.Data[0]);
                        else
                            fillValue = new QChar('\0');

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QUInt64[] vals = new QUInt64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QUInt64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QUInt64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QCharNDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QChar(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QInt64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QInt64NDimArray resVal = new QInt64NDimArray(newDim);
                        QInt64 fillValue;

                        if (isFillValue)
                            fillValue = new QInt64(fillValueArray.Data[0]);
                        else
                            fillValue = new QInt64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QUInt64[] vals = new QUInt64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QUInt64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QUInt64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QInt64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QInt64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QUInt64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QUInt64NDimArray resVal = new QUInt64NDimArray(newDim);
                        QUInt64 fillValue;

                        if (isFillValue)
                            fillValue = new QUInt64(fillValueArray.Data[0]);
                        else
                            fillValue = new QUInt64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QUInt64[] vals = new QUInt64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QUInt64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QUInt64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QUInt64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QUInt64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QFloat64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QFloat64NDimArray resVal = new QFloat64NDimArray(newDim);
                        QFloat64 fillValue;

                        if (isFillValue)
                            fillValue = new QFloat64(fillValueArray.Data[0]);
                        else
                            fillValue = new QFloat64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QUInt64[] vals = new QUInt64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QUInt64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QUInt64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QFloat64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QFloat64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }
                    else
                        throw (new NumericalCalculationsException("??? Undefined function or method 'accumarray' for input arguments of type " +
                            Helper.PrintEnumName(funRes.GetEnumType()) + "."));
                }


                else if (o.ElementAt(1).GetEnumType() == IQLabValueType.QFloat64NDimArray)
                {
                    QFloat64[] val = new QFloat64[n];
                    for (int i = 0; i < n; i++)
                        val[i] = new QFloat64(valArray.Data[x.Value.ElementAt(i)]);

                    funArgs.Add(new QFloat64NDimArray(val, 1, n));
                    funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                    if (funRes.GetEnumType() == IQLabValueType.QBooleanNDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QBooleanNDimArray resVal = new QBooleanNDimArray(newDim);
                        QBoolean fillValue;

                        if (isFillValue)
                            fillValue = new QBoolean(fillValueArray.Data[0]);
                        else
                            fillValue = new QBoolean(false);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QFloat64[] vals = new QFloat64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QFloat64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QFloat64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QBooleanNDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QBoolean(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QCharNDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QCharNDimArray resVal = new QCharNDimArray(newDim);
                        QChar fillValue;

                        if (isFillValue)
                            fillValue = new QChar(fillValueArray.Data[0]);
                        else
                            fillValue = new QChar('\0');

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QFloat64[] vals = new QFloat64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QFloat64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QFloat64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QCharNDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QChar(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QInt64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QInt64NDimArray resVal = new QInt64NDimArray(newDim);
                        QInt64 fillValue;

                        if (isFillValue)
                            fillValue = new QInt64(fillValueArray.Data[0]);
                        else
                            fillValue = new QInt64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QFloat64[] vals = new QFloat64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QFloat64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QFloat64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QInt64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QInt64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QUInt64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QUInt64NDimArray resVal = new QUInt64NDimArray(newDim);
                        QUInt64 fillValue;

                        if (isFillValue)
                            fillValue = new QUInt64(fillValueArray.Data[0]);
                        else
                            fillValue = new QUInt64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QFloat64[] vals = new QFloat64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QFloat64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QFloat64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QUInt64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QUInt64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }

                    else if (funRes.GetEnumType() == IQLabValueType.QFloat64NDimArray)
                    {
                        if (isFillValue && (o.ElementAt(4).GetEnumType() != funRes.GetEnumType()))
                            throw new NumericalCalculationsException("??? Error using ==> accumarray \n FILLVALUE and output from the function '" + fun + "' did not have the same class.");

                        QFloat64NDimArray resVal = new QFloat64NDimArray(newDim);
                        QFloat64 fillValue;

                        if (isFillValue)
                            fillValue = new QFloat64(fillValueArray.Data[0]);
                        else
                            fillValue = new QFloat64(0);

                        for (int i = 0; i < resVal.Data.Length; i++)
                        {
                            List<int> l;
                            bool success = newListOld.TryGetValue(i, out l);

                            if (success)
                            {
                                int nn = l.Count;
                                QFloat64[] vals = new QFloat64[nn];
                                for (int ii = 0; ii < nn; ii++)
                                    vals[ii] = new QFloat64(valArray.Data[l.ElementAt(ii)]);

                                funArgs = new List<IQLabValue>();
                                funArgs.Add(new QFloat64NDimArray(vals, 1, nn));
                                funRes = ((BuiltInFunction)calledFun).f(funArgs).ElementAt(0);

                                resVal.SetDataElement(i, (funRes as QFloat64NDimArray).Data[0]);
                            }
                            else
                                resVal.SetDataElement(i, new QFloat64(fillValue));
                        }

                        res.Add(resVal);
                        return res;
                    }
                    else
                        throw (new NumericalCalculationsException("??? Undefined function or method 'accumarray' for input arguments of type " +
                            Helper.PrintEnumName(funRes.GetEnumType()) + "."));
                }

                else
                    throw (new NumericalCalculationsException("??? Undefined function or method 'accumarray' for input arguments of type " +
                        Helper.PrintEnumName(o.ElementAt(1).GetEnumType()) + "."));
            }
            else
                throw new NotImplementedException();
        }
    }
}
